package com.yyy.options;


import cn.hutool.log.Log;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.junit.Test;

import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

/**
 * options测试
 *
 * @author yiyongyao
 * @date 2023/11/15 11:32
 **/
public class OptionsTest {

    private static final Log log = Log.get();


    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    class Student {
        private String name;
        private Integer age;
        private Set<String> classes;

        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    }

    /**
     * 1.创建optional类的方法
     */
    @Test
    public void createOptional() {
        {//1.1.创建一个空的optional对象
            Optional<Object> empty = Optional.empty();
            log.info("创建一个空的optional对象:{}", empty);
        }


        {
            Student student = new Student();
            // 1.3.创建一个允许空值的optional对象\
            Optional<Object> o = Optional.ofNullable(student);
            log.info("创建一个允许空值的optional对象:{}", o);
            student = null;
            Optional<Object> o1 = Optional.ofNullable(student);
            log.info("创建一个允许空值的optional对象:{}", o1);
        }

        {
            // 1.2.创建一个非空的optional对象
            Student student = new Student();
            Optional<Student> student1 = Optional.of(student);
            log.info("创建一个非空的optional对象:{}", student1);
            //这里会报空指针异常, of方法不允许传入空值
            Optional<Student> student2 = Optional.of(null);
            log.info("创建一个非空的optional对象:{}", student2);
        }

    }

    /**
     * 2.判断Optional容器中是否包含对象
     */
    @Test
    public void ifPresent() {

        {
            Optional<Object> o = Optional.empty();
            log.info("判断Optional容器中是否包含对象:{}", o.isPresent());
            Student student = new Student();
            Optional<Object> o1 = Optional.ofNullable(student);
            log.info("判断Optional容器中是否包含对象:{}", o1.isPresent());
            Optional<Object> o2 = Optional.ofNullable(null);
            log.info("判断Optional容器中是否包含对象:{}", o2.isPresent());

            //如果容器中有对象,则执行ifPresent中的方法
            o.ifPresent(s -> log.info("o判断Optional容器中是否包含对象:{}", s));
            o1.ifPresent(s -> log.info("o1判断Optional容器中是否包含对象:{}", s));
            o2.ifPresent(s -> log.info("o2判断Optional容器中是否包含对象:{}", s));

        }

        {
            String name = null;
            Optional<String> o = Optional.ofNullable(name);
            Optional<String> name1 = Optional.of(name);
            log.info("判断Optional容器中是否包含对象:{}", o.isPresent());
            log.info("判断Optional容器中是否包含对象:{}", name1.isPresent());
        }

    }


    /**
     * 3.获取Optional容器中的对象
     */
    @Test
    public void get() {
        {
            try {
                Student student = new Student();
                Optional<Object> o1 = Optional.ofNullable(student);
                log.info("获取Optional容器中的对象:{}", o1.get());
                Optional<Object> o2 = Optional.ofNullable(null);
                log.info("获取Optional容器中的对象:{}", o2.get()); //会报NoSuchElementException异常, 因为容器中没有对象
                Optional<Object> o = Optional.empty();
                log.info("获取Optional容器中的对象:{}", o.get());  //会报NoSuchElementException异常, 因为容器中没有对象
            } catch (Exception e) {
                log.error("获取Optional容器中的对象异常:{}", e.getMessage());
            }

        }

        {
            //对象为空时,返回默认值, 建议使用 orElse这种方法来获取容器中的对象, 而orElse中只能是一个对象, 不能是一个方法
            Optional<Object> o2 = Optional.ofNullable(null);
            Object object = o2.orElse(new Student("张三", 18));
            log.info("获取Optional容器中的对象:{}", object);

            //区别是 orElse只能返回一个固定的值且每次都会计算, 不问optional是否为null, orElseGet只在optional是空的时候才计算
            //所以更多的时候使用orElseGet, 可以是一个方法, 性能更好
            Optional<Object> o3 = Optional.ofNullable(null);
            Object ob3 = o3.orElseGet(() -> {
                log.info("orElseGet中的方法执行了");
                return new Student("张三", 18);
            });
            log.info("获取Optional容器中的对象:{}", ob3);
        }
    }

    /**
     * 4.过滤Optional容器中的对象
     */
    @Test
    public void filterOptional() {
        {
            //过滤Optional容器中的对象
            Student student = new Student("张三1", 18);
            Optional<Object> o1 = Optional.ofNullable(student);
            o1.filter(s -> s instanceof Student).ifPresent(s -> log.info("过滤Optional容器中的对象:{}", s));
            Object object = o1.filter(s -> ((Student) s).getName().equalsIgnoreCase("张三")).orElseThrow(() -> new RuntimeException("对象不是张三"));
            log.info("过滤Optional容器中的对象:{}", object);
        }
    }

    /**
     * 5.映射Optional容器中的对象
     *
     * @return
     */
    @Test
    public void mapOptional() {
        {
            //过滤Optional容器中的对象
            Student student = new Student("小王", 18);
            Optional<Object> o1 = Optional.ofNullable(student);
            o1.map(s -> ((Student) s).getName()).ifPresent(s -> log.info("映射Optional容器中的对象的属性名字:{}", s));
            String s1 = o1.filter(s -> ((Student) s).getName().equalsIgnoreCase("小王")).map(s -> ((Student) s).getName()).orElseGet(() -> "张三");
            log.info("映射Optional容器中的对象的属性名字:{}", s1);
        }

        {
            //用于返回的对象是一个Optional对象
            String name = "小王1";
            Optional<Object> o = Optional.ofNullable(name).flatMap(s -> getStudent(s));
            o.ifPresent(s -> log.info("映射Optional容器中的对象的属性名字:{}", s));
            o.orElseThrow(() -> new RuntimeException("没有找到小王"));

        }

    }


    public <T> Optional<T> getStudent(String name) {
        if (name.equalsIgnoreCase("小王")) {
            return Optional.of((T) new Student("小王", 18));
        } else {
            return Optional.empty();
        }
    }


    @Test
    public void TestArr() {
        String[] strings = new String[]{"12313", "3434-67676-667677"};
        AtomicReference<String> qrcode = new AtomicReference<>("");
        Optional.of(strings).filter(s -> s.length > 1).map(s -> s[1]).ifPresent(qrcode::set);
        log.info(String.valueOf(qrcode));


        // optional不能判别 list 为 0 的情况. 对集合不建议使用optional的操作, 很容易出问题
        List<Student> list = new ArrayList<>();
        Optional.ofNullable(list).orElseThrow(() -> new RuntimeException("运行异常"));
        Student student = new Student();
        student.setClasses(new HashSet<>());
        Optional.ofNullable(student.getClasses()).orElseThrow(() -> new RuntimeException("运行异常:科目为空"));
    }




    @Test
    public void TestAtomicReference() {

      //写一个原子类 string
        AtomicReference<String> atomicReference = new AtomicReference<>();
        String string = Optional.ofNullable(atomicReference.get()).orElse("错误");
        log.info(string);
    }

}
